package util

import (
	"errors"
	"go_iot/pkg/global"
	"time"

	"github.com/golang-jwt/jwt/v5"
)

var (
	ErrTokenExpired          = errors.New("token is expired")
	ErrTokenNotValidYet      = errors.New("token not active yet")
	ErrTokenMalformed        = errors.New("that's not even a token")
	ErrTokenInvalid          = errors.New("couldn't handle this token")
	ErrUnsupportedSignMethod = errors.New("unsupported sign method")
)

type MyCustomClaims struct {
	Account  string `json:"account"`
	ClientId int    `json:"clientid"`
	IsSystem int    `json:"system"`
	jwt.RegisteredClaims
}

func CreateToken(id int, account, identity string, isSystem int) (string, error) {

	customClaims := &MyCustomClaims{
		Account:  account,
		IsSystem: isSystem,
		ClientId: id,
		RegisteredClaims: jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Duration(global.Conf.Jwt.ExpireTime) * time.Hour)), //过期时间
			IssuedAt:  jwt.NewNumericDate(time.Now()),                                                            //签发时间
			NotBefore: jwt.NewNumericDate(time.Now()),                                                            //最早使用时间
			Issuer:    "iotadmin",                                                                                //签发者
			Subject:   identity,                                                                                  //签发对象
			ID:        account,                                                                                   //id
			Audience:  []string{"pc", "ios", "and", "web"},                                                       //受众对象
		},
	}

	token, err := jwt.NewWithClaims(jwt.SigningMethodHS256, customClaims).SignedString([]byte(global.Conf.Jwt.Key))
	return token, err
}

func ParseToken(tokenString string) (*MyCustomClaims, error) {
	token, err := jwt.ParseWithClaims(tokenString, &MyCustomClaims{}, func(token *jwt.Token) (interface{}, error) {
		return []byte(global.Conf.Jwt.Key), nil
	})

	if err != nil {
		if errors.Is(err, jwt.ErrTokenMalformed) {
			return nil, ErrTokenMalformed
		} else if errors.Is(err, jwt.ErrTokenExpired) {
			// Token is expired
			return nil, ErrTokenExpired
		} else if errors.Is(err, jwt.ErrTokenNotValidYet) {
			return nil, ErrTokenNotValidYet
		} else {
			return nil, ErrTokenInvalid
		}
	}

	if token.Valid {
		if claims, ok := token.Claims.(*MyCustomClaims); ok {
			return claims, nil
		}
	}
	return nil, ErrTokenInvalid

}
